﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Media;
using Blackbird.Common;
using Blackbird.Core.Editable.Frames;
using Blackbird.Core.Editable.Map;
using Blackbird.Studio.Context;
using Blackbird.Studio.Mvvm;
using Blackbird.Studio.ViewModel;

namespace Blackbird.Studio.Control {
    public class ImageGridDesignerViewModel : INotifyPropertyChanged {

        public static ImageGridDesignerViewModel Instance { get; private set; }

        public RelayCommand GrowCommand { get; set; }
        public RelayCommand ShrinkCommand { get; set; }
        public RelayCommand ZoomInCommand { get; set; }
        public RelayCommand ZoomOutCommand { get; set; }

        static ImageGridDesignerViewModel() {
            Instance = new ImageGridDesignerViewModel {
                Model = new ImageGridDesignerModel {
                    Width = 3,
                    Height = 3,
                    Zoom = 1.0,
                    CellHeight = 256,
                    CellWidth = 256
                }
            };
        }

        public ImageGridDesignerViewModel() {
            GrowCommand = new RelayCommand(by => TweakModel(1), o => Model.Height < 10);
            ShrinkCommand = new RelayCommand(by => TweakModel(-1), o => Model.Height > 1);
            ZoomInCommand = new RelayCommand(by => ZoomModel(0.5), o => Model.Zoom < 5.0);
            ZoomOutCommand = new RelayCommand(by => ZoomModel(-0.5), o => Model.Zoom > 0.5);
        }

        private ImageGridDesignerModel _model;
        public ImageGridDesignerModel Model { get { return _model; } set { InvokePropertyChanged("Model", value, () => _model = value); } }

        private void TweakModel(int by)
        {
            Model.Width += by;
            Model.Height += by;
        }

        private void ZoomModel(double by) {
            Model.Zoom += by;
        }
        
        public event PropertyChangedEventHandler PropertyChanged;

        protected void InvokePropertyChanged<T>(string propertyName, T value, Action setValue) {
            var originalValue = GetType().GetProperty(propertyName).GetValue(this, null);
            if ((originalValue == null) || !originalValue.Equals(value)) {
                setValue();
                if (PropertyChanged != null) {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }

    }

    public class ImageGridDesignerModel : Map<EditableStaticMapNode>, INotifyPropertyChanged {
        private bool _generated;

        private int _width;
        private int _height;
        private double _cellWidth;
        private double _cellHeight;
        private double _zoom;

        public int Width { get { return _width; } set { InvokePropertyChanged(value, () => _width = value, "Width"); } }
        public int Height { get { return _height; } set { InvokePropertyChanged(value, () => _height = value, "Height", "Tiles"); } }
        public double CellWidth { get { return _cellWidth; } set { InvokePropertyChanged(value, () => _cellWidth = value, "CellWidth", "Tiles"); } }
        public double CellHeight { get { return _cellHeight; } set { InvokePropertyChanged(value, () => _cellHeight = value, "CellHeight", "Tiles"); } }
        public double Zoom { get { return _zoom; } set { InvokePropertyChanged(value, () => _zoom = value, "Zoom"); } }

        public IEnumerable<ImageSource> Tiles {
            get {
                if (!_generated)
                    GenerateMap();
                return StorageArray.Select(node => node.Frame.BitmapSource);
            }
        }

        public override void Initialize() {
            PropertyChanged += ImageGridDesignerModelPropertyChanged;
        }

        void ImageGridDesignerModelPropertyChanged(object sender, PropertyChangedEventArgs e) {
            if (e.PropertyName == "Height")
                _generated = false;
        }

        private void GenerateMap() {
            DimensionExtents = new[] { Width, Height };
            for (var y = 0; y < Height; y++) {
                for (var x = 0; x < Width; x++) {
                    var node = EntityModelContext.CreateModel<EditableStaticMapNode>();
                    node.Frame = EntityModelContext.CreateModel<EditableFrame>();
                    var text = string.Format("<-- Tile [{0} x {1}] -->", x + 1, y + 1);
                    node.Frame.BitmapSource =
                        DesignerViewModel.GenerateSampleBitmap(text);
                    node.Frame.Name = string.Format("Tile {0}x{1}", x, y);
                    this[x, y] = node;
                }
            }
            _generated = true;
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void InvokePropertyChanged<T>(T value, Action setValue, params string[] propertyNames) {
            var originalValue = GetType().GetProperty(propertyNames[0]).GetValue(this, null);
            if ((originalValue == null) || !originalValue.Equals(value)) {
                setValue();
                if (PropertyChanged != null) {
                    foreach (var propertyName in propertyNames) {
                        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                    }
                }
            }
        }
    }
}
